unity workflows

安装量: 46
排名: #16159

安装

npx skills add https://github.com/cryptorabea/claude_unity_dev_plugin --skill 'Unity Workflows'

Unity Workflows and Editor Tools Essential workflows for Unity editor scripting, input systems, UI development, and asset management. Overview Efficient Unity workflows accelerate development and reduce errors. This skill covers editor customization, modern input handling, UI systems, and asset pipeline optimization. Core workflow areas: Editor scripting and custom tools Input System (new and legacy) UI development (UI Toolkit, uGUI) Asset management and build pipeline Editor Scripting Basics Menu Items Create custom menu commands: using UnityEditor ; public static class CustomMenu { [ MenuItem ( "Tools/My Tool" ) ] private static void ExecuteTool ( ) { Debug . Log ( "Custom tool executed" ) ; } [ MenuItem ( "Tools/My Tool" , true ) ] // Validation private static bool ValidateTool ( ) { return Selection . activeGameObject != null ; } // Keyboard shortcut: Ctrl+Shift+T (Windows), Cmd+Shift+T (Mac) [ MenuItem ( "Tools/Quick Action %#t" ) ] private static void QuickAction ( ) { // Action } } Shortcut keys: % = Ctrl (Cmd on Mac)

= Shift
&
= Alt
_g
= G key
Context Menus
Right-click context menu for GameObjects/Components:
[
MenuItem
(
"GameObject/My Custom Action"
,
false
,
10
)
]
private
static
void
CustomAction
(
)
{
GameObject
selected
=
Selection
.
activeGameObject
;
// Perform action
}
// Component context menu
public
class
MyComponent
:
MonoBehaviour
{
[
ContextMenu
(
"Do Something"
)
]
private
void
DoSomething
(
)
{
Debug
.
Log
(
"Context menu action"
)
;
}
[
ContextMenuItem
(
"Reset Value"
,
"ResetValue"
)
]
[
SerializeField
]
private
int
value
;
private
void
ResetValue
(
)
{
value
=
0
;
}
}
Custom Inspector
Override Inspector for custom types:
[
CustomEditor
(
typeof
(
MyScript
)
)
]
public
class
MyScriptEditor
:
Editor
{
public
override
void
OnInspectorGUI
(
)
{
// Draw default inspector
DrawDefaultInspector
(
)
;
MyScript
script
=
(
MyScript
)
target
;
// Custom button
if
(
GUILayout
.
Button
(
"Execute Action"
)
)
{
script
.
ExecuteAction
(
)
;
}
// Custom fields
EditorGUILayout
.
LabelField
(
"Custom Section"
,
EditorStyles
.
boldLabel
)
;
script
.
customValue
=
EditorGUILayout
.
IntSlider
(
"Custom Value"
,
script
.
customValue
,
0
,
100
)
;
// Apply changes
if
(
GUI
.
changed
)
{
EditorUtility
.
SetDirty
(
target
)
;
}
}
}
Property Drawers
Custom property display in Inspector:
[
System
.
Serializable
]
public
class
Range
{
public
float
min
;
public
float
max
;
}
[
CustomPropertyDrawer
(
typeof
(
Range
)
)
]
public
class
RangeDrawer
:
PropertyDrawer
{
public
override
void
OnGUI
(
Rect
position
,
SerializedProperty
property
,
GUIContent
label
)
{
EditorGUI
.
BeginProperty
(
position
,
label
,
property
)
;
position
=
EditorGUI
.
PrefixLabel
(
position
,
GUIUtility
.
GetControlID
(
FocusType
.
Passive
)
,
label
)
;
var
minProp
=
property
.
FindPropertyRelative
(
"min"
)
;
var
maxProp
=
property
.
FindPropertyRelative
(
"max"
)
;
float
halfWidth
=
position
.
width
/
2
;
Rect
minRect
=
new
Rect
(
position
.
x
,
position
.
y
,
halfWidth
-
5
,
position
.
height
)
;
Rect
maxRect
=
new
Rect
(
position
.
x
+
halfWidth
,
position
.
y
,
halfWidth
-
5
,
position
.
height
)
;
EditorGUI
.
PropertyField
(
minRect
,
minProp
,
GUIContent
.
none
)
;
EditorGUI
.
PropertyField
(
maxRect
,
maxProp
,
GUIContent
.
none
)
;
EditorGUI
.
EndProperty
(
)
;
}
}
EditorWindow
Create custom editor windows:
public
class
MyEditorWindow
:
EditorWindow
{
private
string
textField
=
""
;
private
int
intField
=
0
;
[
MenuItem
(
"Window/My Editor Window"
)
]
private
static
void
ShowWindow
(
)
{
var
window
=
GetWindow
<
MyEditorWindow
>
(
)
;
window
.
titleContent
=
new
GUIContent
(
"My Tool"
)
;
window
.
minSize
=
new
Vector2
(
300
,
200
)
;
window
.
Show
(
)
;
}
private
void
OnGUI
(
)
{
GUILayout
.
Label
(
"My Custom Tool"
,
EditorStyles
.
boldLabel
)
;
textField
=
EditorGUILayout
.
TextField
(
"Text Field"
,
textField
)
;
intField
=
EditorGUILayout
.
IntField
(
"Int Field"
,
intField
)
;
if
(
GUILayout
.
Button
(
"Execute"
)
)
{
Execute
(
)
;
}
}
private
void
Execute
(
)
{
Debug
.
Log
(
$"Executed with:
{
textField
}
,
{
intField
}
"
)
;
}
}
AssetDatabase Operations
Manipulate assets programmatically:
using
UnityEditor
;
public
static
class
AssetUtilities
{
[
MenuItem
(
"Assets/Create Prefab From Selection"
)
]
private
static
void
CreatePrefab
(
)
{
GameObject
selected
=
Selection
.
activeGameObject
;
if
(
selected
==
null
)
return
;
string
path
=
$"Assets/Prefabs/
{
selected
.
name
}
.prefab"
;
// Create prefab
PrefabUtility
.
SaveAsPrefabAsset
(
selected
,
path
)
;
AssetDatabase
.
Refresh
(
)
;
}
public
static
T
LoadAsset
<
T
>
(
string
path
)
where
T
:
UnityEngine
.
Object
{
return
AssetDatabase
.
LoadAssetAtPath
<
T
>
(
path
)
;
}
public
static
void
CreateFolder
(
string
path
)
{
if
(
!
AssetDatabase
.
IsValidFolder
(
path
)
)
{
AssetDatabase
.
CreateFolder
(
System
.
IO
.
Path
.
GetDirectoryName
(
path
)
,
System
.
IO
.
Path
.
GetFileName
(
path
)
)
;
}
}
}
Unity Input System
New Input System Setup
Install: Window > Package Manager > Input System
Create Input Actions:
Create > Input Actions
Add Action Maps (Player, UI, etc.)
Add Actions (Move, Jump, Fire, etc.)
Bind inputs (Keyboard, Gamepad, etc.)
Generate C# class (Inspector > Generate C# Class)
Using Input Actions
using
UnityEngine
.
InputSystem
;
public
class
PlayerController
:
MonoBehaviour
{
private
PlayerInput
playerInput
;
private
InputAction
moveAction
;
private
InputAction
jumpAction
;
private
void
Awake
(
)
{
playerInput
=
GetComponent
<
PlayerInput
>
(
)
;
moveAction
=
playerInput
.
actions
[
"Move"
]
;
jumpAction
=
playerInput
.
actions
[
"Jump"
]
;
}
private
void
OnEnable
(
)
{
jumpAction
.
performed
+=
OnJump
;
}
private
void
OnDisable
(
)
{
jumpAction
.
performed
-=
OnJump
;
}
private
void
Update
(
)
{
Vector2
moveInput
=
moveAction
.
ReadValue
<
Vector2
>
(
)
;
Move
(
moveInput
)
;
}
private
void
OnJump
(
InputAction
.
CallbackContext
context
)
{
Jump
(
)
;
}
private
void
Move
(
Vector2
input
)
{
}
private
void
Jump
(
)
{
}
}
Input Action Asset (Generated C#)
// After generating C# class from Input Actions asset
private
PlayerInputActions
inputActions
;
private
void
Awake
(
)
{
inputActions
=
new
PlayerInputActions
(
)
;
}
private
void
OnEnable
(
)
{
inputActions
.
Player
.
Enable
(
)
;
inputActions
.
Player
.
Jump
.
performed
+=
OnJump
;
}
private
void
OnDisable
(
)
{
inputActions
.
Player
.
Disable
(
)
;
inputActions
.
Player
.
Jump
.
performed
-=
OnJump
;
}
private
void
Update
(
)
{
Vector2
move
=
inputActions
.
Player
.
Move
.
ReadValue
<
Vector2
>
(
)
;
}
Benefits:
Type-safe action access
Auto-completion
Compile-time checking
Legacy Input System
// Still functional, simpler for basic games
private
void
Update
(
)
{
// Keyboard
if
(
Input
.
GetKeyDown
(
KeyCode
.
Space
)
)
Jump
(
)
;
// Mouse
if
(
Input
.
GetMouseButtonDown
(
0
)
)
Fire
(
)
;
// Axis (configured in Edit > Project Settings > Input Manager)
float
horizontal
=
Input
.
GetAxis
(
"Horizontal"
)
;
float
vertical
=
Input
.
GetAxis
(
"Vertical"
)
;
Move
(
new
Vector2
(
horizontal
,
vertical
)
)
;
}
Use for:
Simple prototypes
Mobile touch input
Legacy projects
New Input System preferred for:
Multi-platform support
Rebindable controls
Complex input handling
UI Systems
uGUI (Canvas-Based UI)
Standard Unity UI system:
using
UnityEngine
.
UI
;
using
TMPro
;
// TextMeshPro
public
class
UIManager
:
MonoBehaviour
{
[
SerializeField
]
private
TextMeshProUGUI
scoreText
;
[
SerializeField
]
private
Button
playButton
;
[
SerializeField
]
private
Slider
healthSlider
;
private
void
Start
(
)
{
playButton
.
onClick
.
AddListener
(
OnPlayClicked
)
;
}
private
void
OnDestroy
(
)
{
playButton
.
onClick
.
RemoveListener
(
OnPlayClicked
)
;
}
public
void
UpdateScore
(
int
score
)
{
scoreText
.
text
=
$"Score:
{
score
}
"
;
}
public
void
UpdateHealth
(
float
health
,
float
maxHealth
)
{
healthSlider
.
value
=
health
/
maxHealth
;
}
private
void
OnPlayClicked
(
)
{
Debug
.
Log
(
"Play button clicked"
)
;
}
}
Canvas render modes:
Screen Space - Overlay
UI always on top, no camera needed (fastest)
Screen Space - Camera
UI rendered by camera, supports post-processing
World Space
3D UI in game world UI Optimization: Separate static/dynamic UI to different canvases Disable raycast targets on non-interactive elements Use sprite atlases Minimize Layout Groups (expensive) UI Toolkit (Modern UI) Runtime and Editor UI (Unity 2021+): UXML (UI structure): < ui: UXML

< ui: VisualElement name = " root "

< ui: Label text = " Score: 0 " name = " scoreLabel " /> < ui: Button text = " Play " name = " playButton " /> </ ui: VisualElement

</ ui: UXML

USS (Styling): .root { flex-grow : 1 ; background-color : rgb ( 50 , 50 , 50 ) ; }

scoreLabel

{
font-size
:
24
px
;
color
:
white
;
}
C# (Logic):
using
UnityEngine
.
UIElements
;
public
class
UIController
:
MonoBehaviour
{
private
UIDocument
uiDocument
;
private
Label
scoreLabel
;
private
Button
playButton
;
private
void
Awake
(
)
{
uiDocument
=
GetComponent
<
UIDocument
>
(
)
;
var
root
=
uiDocument
.
rootVisualElement
;
scoreLabel
=
root
.
Q
<
Label
>
(
"scoreLabel"
)
;
playButton
=
root
.
Q
<
Button
>
(
"playButton"
)
;
playButton
.
clicked
+=
OnPlayClicked
;
}
public
void
UpdateScore
(
int
score
)
{
scoreLabel
.
text
=
$"Score:
{
score
}
"
;
}
private
void
OnPlayClicked
(
)
{
Debug
.
Log
(
"Play clicked"
)
;
}
}
Benefits:
Faster performance (retained mode)
Better for complex UI
Modern web-like workflow (HTML/CSS equivalent)
Shared with Editor UI
Use for:
New projects (Unity 2021+)
Complex UI
Editor tools
Asset Management
Addressables
Async asset loading and memory management:
Setup:
Window > Asset Management > Addressables > Groups
Mark assets as Addressable
Organize into groups
Loading assets:
using
UnityEngine
.
AddressableAssets
;
using
UnityEngine
.
ResourceManagement
.
AsyncOperations
;
public
class
AssetLoader
:
MonoBehaviour
{
private
async
void
Start
(
)
{
// Load asset asynchronously
var
handle
=
Addressables
.
LoadAssetAsync
<
GameObject
>
(
"Enemy"
)
;
await
handle
.
Task
;
if
(
handle
.
Status
==
AsyncOperationStatus
.
Succeeded
)
{
GameObject
prefab
=
handle
.
Result
;
Instantiate
(
prefab
)
;
}
// Release when done
Addressables
.
Release
(
handle
)
;
}
// Instantiate directly
private
async
void
SpawnEnemy
(
)
{
var
handle
=
Addressables
.
InstantiateAsync
(
"Enemy"
)
;
await
handle
.
Task
;
GameObject
enemy
=
handle
.
Result
;
// Use enemy
}
}
Benefits:
Async loading (no frame hitches)
Memory management
Remote content updates
Build optimization
Use for:
Large games
DLC/live updates
Mobile games (reduce install size)
Resources Folder (Legacy)
Simple asset loading:
// Load from Resources folder
GameObject
prefab
=
Resources
.
Load
<
GameObject
>
(
"Prefabs/Enemy"
)
;
// All assets include in build - inefficient
Avoid:
Use Addressables instead for new projects.
Build Pipeline
Build Settings
using
UnityEditor
;
using
UnityEditor
.
Build
.
Reporting
;
public
static
class
BuildUtility
{
[
MenuItem
(
"Build/Build Windows"
)
]
private
static
void
BuildWindows
(
)
{
BuildPlayerOptions
options
=
new
BuildPlayerOptions
{
scenes
=
new
[
]
{
"Assets/Scenes/MainMenu.unity"
,
"Assets/Scenes/Game.unity"
}
,
locationPathName
=
"Builds/Windows/Game.exe"
,
target
=
BuildTarget
.
StandaloneWindows64
,
options
=
BuildOptions
.
None
}
;
BuildReport
report
=
BuildPipeline
.
BuildPlayer
(
options
)
;
if
(
report
.
summary
.
result
==
BuildResult
.
Succeeded
)
{
Debug
.
Log
(
$"Build succeeded:
{
report
.
summary
.
totalSize
}
bytes"
)
;
}
else
{
Debug
.
LogError
(
$"Build failed:
{
report
.
summary
.
result
}
"
)
;
}
}
}
Build Preprocessing
using
UnityEditor
.
Build
;
using
UnityEditor
.
Build
.
Reporting
;
public
class
BuildPreprocessor
:
IPreprocessBuildWithReport
{
public
int
callbackOrder
=>
0
;
public
void
OnPreprocessBuild
(
BuildReport
report
)
{
Debug
.
Log
(
"Preprocessing build..."
)
;
// Validate assets
// Update version number
// Generate build info
}
}
Best Practices
DO:
Use Editor scripting to automate repetitive tasks
Implement Custom Inspectors for complex components
Use new Input System for multi-platform projects
Optimize UI with separate canvases for static/dynamic content
Use Addressables for large games and mobile
Create editor tools for designers/artists
Validate assets before builds
DON'T:
Hardcode editor paths (use AssetDatabase)
Forget to unsubscribe from Input System actions
Mix Layout Groups excessively (UI performance killer)
Use Resources folder for new projects (use Addressables)
Create UI in Update loop
Skip editor validation for critical scripts
Golden rule
Automate workflows with editor tools. Time spent creating tools saves exponentially more time in iteration. Apply these workflow optimizations and modern systems for efficient, scalable Unity development.
返回排行榜